package org.nViron.nvCommon;

/**
 * Represents a geo position specified by longitude, latitude and altitude
 * @author Roland Haring <p>
 * <script type="text/javascript" src="http://www.ohloh.net/p/376434/widgets/project_basic_stats.js"></script>
 */
public class nvPosition {
    public class KarthesianCoordinates {
        double x;
        double y;
        double z;
    }
    public final static double CIRCUMFERENCE_EARTH_EQUATOR = 40076592.0;
    public final static double CIRCUMFERENCE_EARTH_POLE    = 40009153.0;
    float                      altitude;
    double                     latitude;

    double                     longitude;

    public nvPosition() {}

    public nvPosition(double _lng, double _lat, float _alt) {
        longitude = _lng;
        latitude  = _lat;
        altitude  = _alt;
    }

    public nvPosition(nvPosition other) {
        longitude = other.getLongitude();
        latitude  = other.getLatitude();
        altitude  = other.getAltitude();
    }

    public void assign(nvPosition other) {
        set(other.getLongitude(), other.getLatitude(), other.getAltitude());
    }

    public double getAbsX() {
        return getLongitude() / 360.0 * CIRCUMFERENCE_EARTH_EQUATOR * Math.cos(latitude * Math.PI / 180.0);
    }

    public double getAbsY() {
        return CIRCUMFERENCE_EARTH_POLE * getLatitude() / 360.0;
    }

    public float getAltitude() {
        return altitude;
    }

    public double getDistance2d(nvPosition other) {
        return Math.sqrt(getDistance2dSqrt(other));
    }

    public double getDistance2dSqrt(nvPosition other) {
        double absXP1 = other.getAbsX();
        double absYP1 = other.getAbsY();
        double absXP2 = getAbsX();
        double absYP2 = getAbsY();

        // calc distance sqr
        return (absXP2 - absXP1) * (absXP2 - absXP1) + (absYP2 - absYP1) * (absYP2 - absYP1);
    }

    public double getDistance3d(nvPosition other) {
        return Math.sqrt(getDistance3dSqrt(other));
    }

    public double getDistance3dSqrt(nvPosition other) {
        KarthesianCoordinates kc1 = getKarthesianCoordinates();
        KarthesianCoordinates kc2 = other.getKarthesianCoordinates();

        // calc distance sqr
        return (kc1.x - kc2.x) * (kc1.x - kc2.x) + (kc1.y - kc2.y) * (kc1.y - kc2.y)
               + (kc1.z - kc2.z) * (kc1.z - kc2.z);
    }

    public KarthesianCoordinates getKarthesianCoordinates() {
        KarthesianCoordinates kc              = new KarthesianCoordinates();
        final double          earthMeanRadius = 6371000.0f;

        kc.x = -1.0 * (earthMeanRadius + getAltitude()) * Math.sin(Math.PI / 2.0 - getLatitude() * Math.PI / 180.0)
               * Math.cos(getLongitude() * Math.PI / 180.0 + Math.PI / 2.0);
        kc.y = (earthMeanRadius + getAltitude()) * Math.cos(Math.PI / 2.0 - getLatitude() * Math.PI / 180.0);
        kc.z = (earthMeanRadius + getAltitude()) * Math.sin(Math.PI / 2.0 - getLatitude() * Math.PI / 180.0)
               * Math.sin(getLongitude() * Math.PI / 180.0 + Math.PI / 2.0);

        return kc;
    }

    public double getLatitude() {
        return latitude;
    }

    public double getLongitude() {
        return longitude;
    }

    public void incAltitude(float delta) {
        altitude += delta;
    }

    public void incLatitude(double delta) {
        latitude += delta;
    }

    public void incLongitude(double delta) {
        longitude += delta;
    }

    public void mulAltitude(float mult) {
        altitude *= mult;
    }

    public void mulLatitude(double mult) {
        latitude *= mult;
    }

    public void mulLongitude(double mult) {
        longitude *= mult;
    }

    public void set(double _lng, double _lat, float _alt) {
        longitude = _lng;
        latitude  = _lat;
        altitude  = _alt;
    }

    public void setAltitude(float altitude) {
        this.altitude = altitude;
    }

    public void setLatitude(double latitude) {
        this.latitude = latitude;
    }

    public void setLongitude(double longitude) {
        this.longitude = longitude;
    }
}



